﻿using System;
using System.Drawing;
using System.Text;
using System.Threading;

namespace Core
{
    /// <summary>
    /// Class for manipulation of the Diablo II window.
    /// </summary>
    /// <author>ejact(thomas)</author>
    public class DiaWinHandler : SendMessenger
    {
        private int _clickdelay = 50;
        private int _keydelay = 40;

        public int minimumGameNameChars = 6;
        public int maximumGameNameChars = 10;
        public int minimumGamePassChars = 4;
        public int maximumGamePassChars = 10;

        public DiaWinHandler(IntPtr windowhandle)
            : base(windowhandle)
        {
        }

        public IntPtr WindowHandle
        {
            get { return this.hWnd; }
            set { this.hWnd = value; }
        }

        public int ClickDelay
        {
            get { return this._clickdelay; }
            set { this._clickdelay = value; }
        }

        public int KeyDelay
        {
            get { return this._keydelay; }
            set { this._keydelay = value; }
        }

        public void Login(string password)
        {
            System.Threading.Thread.Sleep(1000);
            this.FillText(password);
            this.SendReturn();
        }

        public void Login(string account, string password)
        {
            System.Threading.Thread.Sleep(2000);
            this.FillText(password);
            this.SendTab();
            this.FillText(account);
            System.Threading.Thread.Sleep(250);
            this.SendReturn();
        }

        public void SelectChar(int charpos)
        {
            System.Threading.Thread.Sleep(1500);
            this.DoubleClick(ClickRegion.CHAR_SEL[charpos]);
        }

        public void CreateNewChar(string p_charname, int charpos)
        {
            System.Threading.Thread.Sleep(1000);
            this.Click(ClickRegion.CREATE_CHAR);
            System.Threading.Thread.Sleep(2000);
            this.Click(ClickRegion.SELECT_ZON_CLASS);
            System.Threading.Thread.Sleep(1000);
            if (! (p_charname == ""))
                this.FillText(p_charname + RandomString(RandomNumber((this.maximumGameNameChars - p_charname.Length - 1), (this.maximumGameNameChars - p_charname.Length))));
            else
                this.FillText(RandomString(RandomNumber(this.minimumGameNameChars, this.maximumGameNameChars)));
            this.SendReturn();
        }

        public void JoinChat()
        {
            this.Click(ClickRegion.ENTER_CHAT);
            Thread.Sleep(500);
        }

        public void JoinChannel(string channel)
        {
            this.Click(ClickRegion.ENTER_CHAT);
            Thread.Sleep(500);
            this.FillText("/j " + channel);
            this.SendReturn();
        }

        public void ChatChannel(string msg)
        {
            this.FillText(msg);
            this.SendReturn();
        }

        public string CreateGame(string gamename, string gamepass, int difficulty)
        {
            this.Click(ClickRegion.CREATE);
            this.Click(ClickRegion.CREATE_GAME_NAME);
            this.FillText(gamename);
            this.Click(ClickRegion.CREATE_GAME_PASS);
            this.FillText(gamepass);
            this.Click(ClickRegion.CREATE_DIFFICULTY[difficulty]);
            this.Click(ClickRegion.CREATE_GAME);
            return gamename;
        }

        public string CreateRandomGame(int difficulty)
        {
            string gamename = RandomString(RandomNumber(this.minimumGameNameChars, this.maximumGameNameChars));
            string gamepass = RandomString(RandomNumber(this.minimumGamePassChars, this.maximumGamePassChars));
            this.CreateGame(gamename, gamepass, difficulty);
            return gamename;
        }

        public string JoinGame(string gamename, string gamepass)
        {
            this.Click(ClickRegion.JOIN);
            System.Threading.Thread.Sleep(500);
            this.Click(ClickRegion.JOIN_GAME_NAME);
            this.FillText(gamename);
            this.Click(ClickRegion.JOIN_GAME_PASS);
            this.FillText(gamepass);
            System.Threading.Thread.Sleep(500);
            this.Click(ClickRegion.JOIN_GAME);
            return gamename;
        }

        public void ChangeDiaWinTitle(string title)
        {
            this.SendWMText(title);
        }

        public void BringDiaToFront()
        {
            this.BringAppToFront();
        }

        public void RemoveLoginError()
        {
            Thread.Sleep(500);
            this.Click(ClickRegion.LOGIN_INVALID_INFO);
        }

        #region Private Functions

        private bool Click(Region region)
        {
            if (this.hWnd != IntPtr.Zero)
            {
                Point p = region.getRandomCoordinate();
                this.SendLeftMouseClick(p.X, p.Y, RandomNumber(this._clickdelay, this._clickdelay * 2));
                return true;
            }
            return false;
        }

        private bool Click(int x, int y)
        {
            return this.Click(new Region(x, y, x, y, ""));
        }

        private bool DoubleClick(Region region)
        {
            if (this.hWnd != IntPtr.Zero)
            {
                Point p = region.getRandomCoordinate();
                this.SendLeftMouseClick(p.X, p.Y, RandomNumber(this._clickdelay, this._clickdelay * 2));
                this.SendLeftMouseClick(p.X, p.Y, RandomNumber(this._clickdelay, this._clickdelay * 2));
                return true;
            }
            return false;
        }

        private bool DoubleClick(int x, int y)
        {
            return this.DoubleClick(new Region(x, y, x, y, ""));
        }

        private bool MoveMouse(int x, int y)
        {
            if (this.hWnd != IntPtr.Zero)
            {
                this.MouseMove(x, y);
                return true;
            }
            return false;
        }

        private bool SendReturn()
        {
            if (this.hWnd != IntPtr.Zero)
            {
                this.SendKey(VK.VK_RETURN, RandomNumber(this._keydelay, this._keydelay * 2));
                return true;
            }
            return false;
        }

        private bool SendTab()
        {
            if (this.hWnd != IntPtr.Zero)
            {
                this.SendKey(VK.VK_TAB, RandomNumber(this._keydelay, this._keydelay * 2));
                return true;
            }
            return false;
        }

        private bool FillText(string msg)
        {
            if (this.hWnd != IntPtr.Zero)
            {
                this.SendText(msg, RandomNumber(this._keydelay, this._keydelay * 2));
                return true;
            }
            return false;
        }

        public string RandomString(int size)
        {
            StringBuilder builder = new StringBuilder();
            Random random = new Random();
            for (int i = 0; i < size; i++)
                builder.Append(Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))));
            return builder.ToString().ToLower();
        }

        public int RandomNumber(int min, int max)
        {
            return new Random().Next(min, max);
        }

        #endregion
    }

    #region Click Regions

    static class ClickRegion
    {
        public static Region ENTER_CHAT = new Region(29, 461, 145, 480, "ENTER_CHAT");
        public static Region JOIN = new Region(656, 452, 767, 467, "JOIN");
        public static Region CREATE = new Region(537, 452, 648, 467, "CREATE");
        public static Region LOGIN = new Region(334, 464, 478, 475, "LOGIN");
        public static Region LOGIN_PASS = new Region(333, 386, 465, 395, "LOGIN_PASS");
        public static Region LOGIN_ACCOUNT = new Region(330, 332, 462, 342, "LOGIN_ACCOUNT");
        public static Region LOGIN_INVALID_INFO = new Region(356, 390, 444, 405, "LOGIN_INVALID_INFO");
        public static Region CREATE_GAME = new Region(600, 405, 763, 429, "CREATE_GAME");
        public static Region CREATE_GAME_PASS = new Region(432, 197, 580, 212, "CREATE_GAME_PASS");
        public static Region CREATE_GAME_NAME = new Region(432, 142, 580, 161, "CREATE_GAME_NAME");
        public static Region EXIT_GAME_SAFE_REGION = new Region(10, 360, 780, 490, "EXIT_GAME_SAFE_REGION");
        public static Region CREATE_CHAR = new Region(62, 482, 177, 518, "CREATE_CHARACTER");
        public static Region JOIN_GAME = new Region(600, 405, 763, 429, "JOIN_GAME");
        public static Region JOIN_GAME_NAME = new Region(429, 129, 588, 146, "JOIN_GAME_NAME");
        public static Region JOIN_GAME_PASS = new Region(604, 129, 735, 140, "JOIN_GAME_PASS");
        public static Region SELECT_ZON_CLASS = new Region(86, 274, 113, 333, "SELECT_ZON_CLASS");

        public static Region[] CREATE_DIFFICULTY =
        {
            new Region(703, 369, 711, 377, "CREATE_HELL"),
            new Region(560, 369, 568, 377, "CREATE_NIGHTMARE"),
            new Region(434, 369, 442, 377, "CREATE_NORMAL")
        };

        public static Region[] CHAR_SEL =
        {
	        new Region(41,92,305,176, "Character_1"),
	        new Region(312,92,576,176, "Character_2"),
	        new Region(41,185,305,269, "Character_3"),
	        new Region(312,185,576,269, "Character_4"),
	        new Region(41,276,305,360, "Character_5"),
	        new Region(312,276,576,360, "Character_6"),
	        new Region(41,370,305,454, "Character_7"),
	        new Region(312,370,576,454, "Character_8")
        };
    }

    class Region
    {
        private int x1;
        private int y1;
        private int x2;
        private int y2;
        public string name;

        public Region(int x1, int y1, int x2, int y2, string name)
        {
            this.x1 = x1;
            this.x2 = x2;
            this.y1 = y1;
            this.y2 = y2;
            this.name = name;
        }

        public Point getRandomCoordinate()
        {
            System.Random random = new System.Random();
            int x = random.Next(this.x1, this.x2);
            int y = random.Next(this.y1, this.y2);
            return new Point(x, y);
        }
    }

    #endregion
}
